Skip to content

Conversation

@heemankv
Copy link
Contributor

@heemankv heemankv commented Nov 15, 2025

Fix: Reset block production executor state after chain reorg

Pull Request Type

  • Bugfix
  • Refactoring (no functional changes, no API changes)

Problem Statement

When the revertTo RPC method was called while Madara was actively in block production state, the system encountered errors. The root cause was that the block production executor maintained stale state after the database was reverted:

  • The executor's state adapter still pointed to the pre-revert chain state
  • Pending transactions in the execution queue belonged to blocks that had just been reverted
  • Block state flags (gas consumed, empty block status) were inconsistent with the new chain tip
  • Attempting to continue block production with this stale state caused execution errors and inconsistencies

Solution

Implemented a state reset mechanism for the block production executor that triggers after chain reorganizations:

Core Changes

  1. Added Reset Command: Introduced a new ResetState executor command that:

    • Reinitializes the state adapter from the current database state
    • Clears all pending transactions from the execution queue
    • Resets block state tracking flags (gas consumed, block empty status)
    • Transitions the executor to a clean NewBlock state
    • Uses continue to naturally re-enter the wait loop for new transactions
  2. RPC Integration: The revertTo RPC method now calls reset_state() on the block production handle after reverting the chain, ensuring the executor state stays synchronized with the database state.

  3. State Synchronization: Added StateReset message to notify the block production task when the executor has been reset, allowing proper state machine transitions.

Additional Improvements

  • Refactored custom header access: Moved get_custom_header() methods to impl<D: MadaraStorageRead> block to make them available for all storage trait bounds, eliminating manual mutex lock patterns throughout the codebase
  • Cleaned up logging: Removed verbose debug tracing statements while retaining essential operational logs
  • Code simplification: Eliminated redundant intermediate variables and manual lock handling

Does this introduce a breaking change?

No

Other Information

The fix ensures that block production can safely resume after any chain reorganization triggered by the revertTo RPC, with all executor state properly synchronized to the new chain tip.

@heemankv heemankv self-assigned this Nov 15, 2025
@heemankv heemankv changed the title update: fixed RevertTo for Sequencer Mode Fix: Reset block production executor state after chain reorg Nov 15, 2025
@heemankv heemankv added the bug Report an issue or unexpected behavior label Nov 15, 2025
@heemankv heemankv marked this pull request as ready for review November 18, 2025 14:08
Copy link
Member

@Mohiiit Mohiiit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what would happen to the l1->l2 deposits? will it get reverted in the bridge as well?

what about withdrawals? (Ik we will have a window of some time before that could happen)

is this for replay-service only?

I think revertTO in sequencer mode should specify the assumption it's making

// Reset the executor state to NewBlock with the fresh state adapter
state = ExecutorThreadState::NewBlock(ExecutorStateNewBlock {
state_adaptor: new_state_adaptor,
consumed_l1_to_l2_nonces: HashSet::new(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what would happen to the nonces that were in the hasmap earlier? will those nonces get saved in the db?

Comment on lines 296 to 297
let latest_block_n = new_state_adaptor.previous_block_n();
tracing::info!("✅ State adapter reinitialized to block_n={}", new_state_adaptor.block_n());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

latest_block_n and block_n() are different blocks?

Comment on lines +17 to +21

*.rs
*.toml
Cargo.toml
Cargo.lock
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so prettier is for .js, .md files only?

Comment on lines 112 to 124
let bp_status = self.ctx.service_status(MadaraServiceId::BlockProduction);
if matches!(bp_status, mp_utils::service::MadaraServiceStatus::On) {
if let Some(block_prod_handle) = &self.block_prod_handle {
tracing::debug!("revertTo: resetting block production state");
block_prod_handle
.reset_state()
.await
.context("Resetting block production executor state after reorg")
.map_err(StarknetRpcApiError::from)?;
tracing::debug!("revertTo: block production state reset complete");
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is business logic, should not live in the rpc crate


// Reset block production executor state if block production is enabled
let bp_status = self.ctx.service_status(MadaraServiceId::BlockProduction);
if matches!(bp_status, mp_utils::service::MadaraServiceStatus::On) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need to check if service is on?

super::ExecutorCommand::ResetState(callback) => {
tracing::info!("🔄 Resetting executor state after reorg");
// Reinitialize the state adapter from the current database state
let new_state_adaptor = match mc_exec::LayeredStateAdapter::new(self.backend.clone()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can just do state = initial_state(), send the message StateReset and return from callback. all resetting of values isn't needed imo.

@apoorvsadana
Copy link
Contributor

as discussed, let's consider switching BPS off and on inside revertTo itself

@heemankv heemankv marked this pull request as draft November 23, 2025 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Report an issue or unexpected behavior

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

4 participants